﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using HYCodeBase.Geometry;
using HYCodeBase.Math;
using HYRevitCode.CurveUtility;

namespace HYRevitCode.RevitTopologySuite
{
	internal static class GeometryTransformer
	{
		internal static bool TryMakeRevitPolygonData(HYPolygon inputPolygon, double useZ, out RevitPolygonDataBean creatResult, List<Arc> lstPotentialArc = null)
		{
			creatResult = null;
			List<Curve> list = null;
			List<List<Curve>> list2 = null;
			List<Curve> list3 = null;
			if (!GeometryTransformer.TryMakeRevitListCurve(inputPolygon.ShellPoints, useZ, out list, lstPotentialArc, false))
			{
				return false;
			}
			if (inputPolygon.LstHolPoints != null && inputPolygon.LstHolPoints.Count != 0)
			{
				list2 = new List<List<Curve>>();
				foreach (HYMulPointXYZ inputPoints in inputPolygon.LstHolPoints)
				{
					list3 = null;
					if (!GeometryTransformer.TryMakeRevitListCurve(inputPoints, useZ, out list3, lstPotentialArc, false))
					{
						return false;
					}
					if (list3 != null)
					{
						list2.Add(list3);
					}
				}
			}
			if (list.Count > 0)
			{
				creatResult = new RevitPolygonDataBean(list, list2);
			}
			return true;
		}

		internal static bool TryMakeRevitListCurve(HYMulPointXYZ inputPoints, double useZ, out List<Curve> creatResult, List<Arc> lstPotentialArc = null, bool ifLinkEndToStart = false)
		{
			creatResult = null;
			if (inputPoints == null)
			{
				return false;
			}
			List<XYZ> list = new List<XYZ>();
			creatResult = new List<Curve>();
			Curve curve = null;
			ArcBackBean arcBackBean = null;
			try
			{
				foreach (HYPointXYZ inputPoint in inputPoints)
				{
					list.Add(GeometryTransformer.TransformPoint(inputPoint, useZ));
				}
			}
			catch (Exception)
			{
				return false;
			}
			if (list.Count < 2)
			{
				return false;
			}
			bool result;
			try
			{
				Dictionary<Arc, double> dictionary = new Dictionary<Arc, double>();
				for (int i = 0; i < GeometryTransformer.CalculateUseSize(ifLinkEndToStart, list); i++)
				{
					curve = null;
					XYZ tempNowPoint;
					XYZ tempNextPoint;
					if (i != list.Count - 1)
					{
						tempNowPoint = list[i];
						tempNextPoint = list[i + 1];
					}
					else
					{
						tempNowPoint = list[i];
						tempNextPoint = list[0];
					}
					GeometryTransformer.TakeCurveBack(lstPotentialArc, ref curve, ref arcBackBean, tempNowPoint, tempNextPoint, ref i, ref creatResult, ref list, ref dictionary);
					if (null != curve)
					{
						creatResult.Add(curve);
					}
				}
				if (arcBackBean != null)
				{
					curve = arcBackBean.GetBackArc();
					if (null != curve)
					{
						creatResult.Add(curve);
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		internal static XYZ TransformPoint(HYPointXYZ inputPoint, double useZ)
		{
			if (inputPoint == null)
			{
				throw new System.ArgumentNullException();
			}
			return new XYZ(inputPoint.X, inputPoint.Y, useZ);
		}

		private static void TakeCurveBack(List<Arc> lstPotentialArc, ref Curve tempCreatCurve, ref ArcBackBean tempArcBean, XYZ tempNowPoint, XYZ tempNextPoint, ref int indexOfPoint, ref List<Curve> lstCreatedCurves, ref List<XYZ> lstUsedPoints, ref Dictionary<Arc, double> tempDic)
		{
			if (tempArcBean == null)
			{
				if (lstPotentialArc != null)
				{
					foreach (Arc arc in lstPotentialArc)
					{
						if (CurveUtilityMethod.IfPointOnCurve(arc, tempNowPoint, true) && CurveUtilityMethod.IfPointOnCurve(arc, tempNextPoint, true) && GeometryTransformer.IfPointOnArcAppendCheck(arc, tempNowPoint, tempNextPoint, ref tempDic, 2.0))
						{
							tempArcBean = new ArcBackBean(arc);
							tempArcBean.AppendPoint(tempNowPoint);
							tempArcBean.AppendPoint(tempNextPoint);
						}
					}
				}
				if (tempArcBean == null)
				{
					tempCreatCurve = GeometryTransformer.TryCreatLine(tempNowPoint, tempNextPoint);
					if (null == tempCreatCurve)
					{
						GeometryTransformer.JustShortLine(tempNowPoint, tempNextPoint, ref tempCreatCurve, ref indexOfPoint, ref lstCreatedCurves, ref lstUsedPoints);
						return;
					}
				}
			}
			else
			{
				if (tempArcBean.IfPointOnThisArc(tempNextPoint))
				{
					tempArcBean.AppendPoint(tempNextPoint);
					return;
				}
				try
				{
					tempCreatCurve = tempArcBean.GetBackArc();
				}
				catch (Exception)
				{
					tempCreatCurve = null;
				}
				tempArcBean = null;
				indexOfPoint--;
			}
		}

		private static int CalculateUseSize(bool ifEndLinkToStart, List<XYZ> inputLst)
		{
			if (!ifEndLinkToStart)
			{
				return inputLst.Count - 1;
			}
			return inputLst.Count;
		}

		private static Curve TryCreatLine(XYZ tempNowPoint, XYZ tempNextPoint)
		{
			Curve result;
			try
			{
				result = Line.CreateBound(tempNowPoint, tempNextPoint);
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		private static bool IfPointOnArcAppendCheck(Arc inputArc, XYZ inputOne, XYZ inputTwo, ref Dictionary<Arc, double> dicTempDistance, double useFactory = 2.0)
		{
			double num = inputOne.DistanceTo(inputTwo);
			double num2 = 0.0;
			if (!dicTempDistance.TryGetValue(inputArc, out num2))
			{
				List<XYZ> list = inputArc.Tessellate().ToList<XYZ>();
				double num3 = 0.0;
				for (int i = 0; i < list.Count - 1; i++)
				{
					num3 += list[i].DistanceTo(list[i + 1]);
				}
				num3 /= (double)(list.Count - 1);
				dicTempDistance.Add(inputArc, num3);
				num2 = num3;
			}
			return num < useFactory * num2;
		}

		private static void JustShortLine(XYZ tempNowPoint, XYZ tempNextPoint, ref Curve tempCreatCurve, ref int indexOfPoint, ref List<Curve> lstCreatedCurves, ref List<XYZ> lstUsedPoints)
		{
			XYZ xyz = (tempNextPoint - tempNowPoint).Normalize();
			Curve curve = null;
			if (lstCreatedCurves.Count > 0)
			{
				curve = lstCreatedCurves[lstCreatedCurves.Count - 1];
			}
			if (null != curve && curve is Line && (curve as Line).Direction.IsAlmostEqualTo(xyz, MathUtility.GetPrecision(4)))
			{
				XYZ endPoint = curve.GetEndPoint(0);
				tempCreatCurve = GeometryTransformer.TryCreatLine(endPoint, tempNextPoint);
				if (null != tempCreatCurve)
				{
					lstCreatedCurves.RemoveAt(lstCreatedCurves.Count - 1);
					return;
				}
			}
			else
			{
				tempCreatCurve = null;
				if (indexOfPoint < lstUsedPoints.Count - 1)
				{
					lstUsedPoints.RemoveAt(indexOfPoint + 1);
					indexOfPoint--;
				}
			}
		}

		internal static bool TryMakeHYPolygon(RevitPolygonDataBean input, out HYPolygon creatResult, int usePrecisionDegree = 3)
		{
			creatResult = null;
			if (input == null)
			{
				return false;
			}
			if (input.ThisPolygon != null)
			{
				creatResult = input.ThisPolygon;
				return true;
			}
			HYMulPointXYZ inputShell = null;
			List<HYMulPointXYZ> list = null;
			HYMulPointXYZ item = null;
			if (!GeometryTransformer.TryMakeHYMulPoint(input.LstRevitCurve, out inputShell, true, true, usePrecisionDegree))
			{
				return false;
			}
			if (input.LstlstHolesCurves != null && input.LstlstHolesCurves.Count != 0)
			{
				list = new List<HYMulPointXYZ>();
				using (List<List<Curve>>.Enumerator enumerator = input.LstlstHolesCurves.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						if (!GeometryTransformer.TryMakeHYMulPoint(enumerator.Current, out item, true, true, usePrecisionDegree))
						{
							return false;
						}
						list.Add(item);
					}
				}
			}
			creatResult = new HYPolygon(inputShell, list);
			input.ThisPolygon = creatResult;
			return true;
		}

		internal static bool TryMakeHYMulPoint(Curve input, out HYMulPointXYZ creatResult, bool ifUseZeroZ = true, int usePrecisionDegree = 3)
		{
			creatResult = null;
			if (null == input)
			{
				return false;
			}
			List<HYPointXYZ> lstInputPoints = new List<HYPointXYZ>();
			if (!GeometryTransformer.TryMakeListHYPoint(input, out lstInputPoints, true, ifUseZeroZ, usePrecisionDegree))
			{
				return false;
			}
			try
			{
				creatResult = new HYMulPointXYZ(lstInputPoints);
			}
			catch (Exception)
			{
				creatResult = null;
				return false;
			}
			return true;
		}

		private static bool TryMakeHYMulPoint(List<Curve> input, out HYMulPointXYZ creatResult, bool ifIsClose = true, bool ifUseZeroZ = true, int usePrecisionDegree = 3)
		{
			creatResult = null;
			if (input == null || input.Count == 0)
			{
				return false;
			}
			List<HYPointXYZ> list = new List<HYPointXYZ>();
			List<HYPointXYZ> collection = new List<HYPointXYZ>();
			for (int i = 0; i < input.Count; i++)
			{
				bool ifUseFinalEndPoint = i == input.Count - 1 || !ifIsClose;
				if (!GeometryTransformer.TryMakeListHYPoint(input[i], out collection, ifUseFinalEndPoint, ifUseZeroZ, usePrecisionDegree))
				{
					return false;
				}
				list.AddRange(collection);
			}
			creatResult = new HYMulPointXYZ(list);
			return true;
		}

		private static bool TryMakeListHYPoint(Curve input, out List<HYPointXYZ> creatResult, bool ifUseFinalEndPoint = false, bool ifUseZeroZ = true, int usePrecisionDegree = 3)
		{
			creatResult = null;
			if (null == input || !input.IsBound)
			{
				return false;
			}
			creatResult = new List<HYPointXYZ>();
			try
			{
				if (input is Arc)
				{
					for (int i = 0; i < input.Tessellate().Count; i++)
					{
						creatResult.Add(GeometryTransformer.TransformPoint(input.Tessellate()[i], ifUseZeroZ, usePrecisionDegree));
					}
				}
				else
				{
					creatResult.Add(GeometryTransformer.TransformPoint(input.GetEndPoint(0), ifUseZeroZ, usePrecisionDegree));
				}
				if (ifUseFinalEndPoint)
				{
					if (input is Arc)
					{
						creatResult.Add(GeometryTransformer.TransformPoint(input.Tessellate()[input.Tessellate().Count - 1], ifUseZeroZ, usePrecisionDegree));
					}
					else
					{
						creatResult.Add(GeometryTransformer.TransformPoint(input.GetEndPoint(1), ifUseZeroZ, usePrecisionDegree));
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private static HYPointXYZ TransformPoint(XYZ input, bool ifUseZeroZ = true, int usePrecisionDegree = 3)
		{
			if (input == null)
			{
				throw new System.ArgumentNullException();
			}
			if (ifUseZeroZ)
			{
				return new HYPointXYZ(input.X, input.Y, 0.0, false, usePrecisionDegree);
			}
			return new HYPointXYZ(input.X, input.Y, input.Z, false, usePrecisionDegree);
		}
	}
}
